#wxwork/wxwork_route.py
import logging
from datetime import datetime, timedelta

import requests
from flask import render_template, request, redirect, url_for, flash, jsonify, Blueprint
from flask_login import login_required, current_user, login_user
from inc.models import db, Department, User, SyncLog, WechatConfig, Group, GroupUser,AdminMember
from admin.wxwork.wxwork_sync import WeComSync  # 使用绝对导入

# 创建蓝图
wx_bp = Blueprint('wxwork', __name__, url_prefix='/admin/wxwork')

# 配置日志
logger = logging.getLogger('WechatSync')


@wx_bp.route('/login')
def wechat_login():
    """企业微信登录入口"""
    config = WechatConfig.query.first()
    if not config or not config.login_enabled:
        flash('企业微信登录未启用', 'danger')
        return redirect(url_for('admin.login'))

    # 生成随机state参数，防止CSRF攻击
    import secrets
    state = secrets.token_urlsafe(16)
    session['wechat_login_state'] = state

    # 构建企业微信登录URL
    redirect_uri = url_for('wxwork.wechat_login_callback', _external=True)
    if config.login_redirect_uri:
        redirect_uri = config.login_redirect_uri

    auth_url = f"https://open.weixin.qq.com/connect/oauth2/authorize?appid={config.corp_id}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_userinfo&state={state}#wechat_redirect"

    return redirect(auth_url)


@wx_bp.route('/login/callback')
def wechat_login_callback():
    """企业微信登录回调"""
    # 验证state参数
    state = request.args.get('state')
    if state != session.get('wechat_login_state'):
        flash('登录状态验证失败', 'danger')
        return redirect(url_for('admin.login'))

    # 获取授权码
    code = request.args.get('code')
    if not code:
        flash('登录失败：未获取到授权码', 'danger')
        return redirect(url_for('admin.login'))

    # 获取访问令牌
    config = WechatConfig.query.first()
    if not config:
        flash('企业微信配置未找到', 'danger')
        return redirect(url_for('admin.login'))

    token_url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={config.corp_id}&corpsecret={config.corp_secret}"
    try:
        response = requests.get(token_url, timeout=10)
        data = response.json()

        if data.get('errcode') != 0:
            flash(f'获取访问令牌失败: {data.get("errmsg")}', 'danger')
            return redirect(url_for('admin.login'))

        access_token = data['access_token']

        # 获取用户信息
        userinfo_url = f"https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token={access_token}&code={code}"
        response = requests.get(userinfo_url, timeout=10)
        userinfo_data = response.json()

        if userinfo_data.get('errcode') != 0:
            flash(f'获取用户信息失败: {userinfo_data.get("errmsg")}', 'danger')
            return redirect(url_for('admin.login'))

        user_id = userinfo_data.get('UserId')
        if not user_id:
            flash('未获取到用户ID', 'danger')
            return redirect(url_for('admin.login'))

        # 查找用户
        user = User.query.filter_by(wecom_userid=user_id).first()
        if not user:
            flash('未找到对应用户', 'danger')
            return redirect(url_for('admin.login'))

        # 查找关联的管理员用户
        admin_member = AdminMember.query.filter_by(wecom_userid=user_id).first()
        if not admin_member or not admin_member.admin_user:
            flash('用户未关联管理员账号', 'danger')
            return redirect(url_for('admin.login'))

        # 登录用户
        admin_user = admin_member.admin_user
        login_user(admin_user)

        # 更新最后登录时间
        admin_user.last_login = datetime.now()
        db.session.commit()

        # 记录登录操作
        OperationLog.create(
            admin_id=admin_user.id,
            action="企业微信登录",
            resource="Auth",
            details=f"用户 {admin_user.username} 通过企业微信登录",
            success=True,
            ip_address=request.remote_addr
        )

        flash('登录成功', 'success')
        return redirect(url_for('admin.index'))

    except Exception as e:
        logger.exception("企业微信登录失败")
        flash(f'登录失败: {str(e)}', 'danger')
        return redirect(url_for('admin.login'))



# 微信首页 - 显示同步日志
@wx_bp.route('/')
def wxindex():
    # 计算统计数据
    department_count = Department.query.count()
    member_count = User.query.count()
    group_count = Group.query.count()

    latest_sync = SyncLog.query.order_by(SyncLog.sync_time.desc()).first()
    sync_logs = SyncLog.query.order_by(SyncLog.sync_time.desc()).limit(10).all()

    # 获取上次同步时间
    last_sync_time = latest_sync.sync_time if latest_sync else None

    # 添加待处理成员数据（未加入任何群组的用户）
    joined_user_ids = {gu.user_id for gu in GroupUser.query.filter(GroupUser.status == 1).all()}  # 修改为数字状态
    # 获取未加入群组的用户
    pending_members = User.query.filter(~User.id.in_(joined_user_ids)).limit(5).all()

    # 添加失败操作数据
    failed_operations = GroupUser.query.filter(GroupUser.status == 0).order_by(  # 修改为数字状态
        GroupUser.joined_at.desc()).limit(5).all()

    return render_template('admin/wxwork/wxindex.html',
                           active_page='index',
                           department_count=department_count,
                           member_count=member_count,
                           group_count=group_count,
                           last_sync_time=last_sync_time,
                           logs=sync_logs,
                           pending_members=pending_members,
                           failed_operations=failed_operations,
                           latest_sync=latest_sync,
                           sync_logs=sync_logs)

# 系统设置
@wx_bp.route('/system', methods=['GET', 'POST'])
def system_config():
    config = WechatConfig.query.first()
    if not config:
        config = WechatConfig()
        db.session.add(config)
        db.session.commit()

    if request.method == 'POST':
        config.corp_id = request.form['corp_id']
        config.corp_secret = request.form['corp_secret']
        config.agent_id = request.form.get('agent_id')

        # 保存同步设置
        config.auto_sync = request.form.get('autoSync') == 'on'
        if 'syncInterval' in request.form:
            config.sync_interval = int(request.form['syncInterval'])

        # 保存扫码登录设置
        config.login_enabled = request.form.get('loginEnabled') == 'on'
        config.login_redirect_uri = request.form.get('loginRedirectUri', '')

        config.access_token = None
        config.token_expires = None
        db.session.commit()
        flash('配置已保存，请刷新Token', 'success')
        return redirect(url_for('wxwork.system_config'))

    sync_logs = SyncLog.query.order_by(SyncLog.sync_time.desc()).limit(5).all() or []
    latest_sync = SyncLog.query.order_by(SyncLog.sync_time.desc()).first()

    # 计算下次同步时间
    next_sync_time = None
    if config.auto_sync and config.sync_interval:
        last_sync_time = latest_sync.sync_time if latest_sync else datetime.now()
        next_sync_time = last_sync_time + timedelta(hours=config.sync_interval)

    return render_template('admin/wxwork/system.html',
                           config=config,
                           sync_logs=sync_logs,
                           latest_sync=latest_sync,
                           next_sync_time=next_sync_time)

# 同步组织架构
@wx_bp.route('/sync', methods=['POST'])
def sync_organization():
    try:
        sync = WeComSync()
        success = sync.sync_departments_and_users()

        if success:
            flash('同步成功', 'success')
        else:
            flash('同步失败，请查看日志', 'danger')
    except Exception as e:
        logger.exception("同步组织架构时发生异常")
        flash(f'同步失败: {str(e)}', 'danger')

    return redirect(url_for('wxwork.wxindex'))

# 刷新Token路由
@wx_bp.route('/refresh_token', methods=['POST'])
def refresh_token():
    try:
        config = WechatConfig.query.first()
        if not config:
            return jsonify({'success': False, 'message': '请先配置企业微信信息'}), 400

        if not config.corp_id or not config.corp_secret:
            return jsonify({'success': False, 'message': '企业ID或Secret未设置'}), 400

        url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={config.corp_id}&corpsecret={config.corp_secret}"
        logger.debug(f"请求Token URL: {url}")
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()
            data = response.json()
        except requests.exceptions.RequestException as e:
            return jsonify({'success': False, 'message': f'API请求失败: {str(e)}'}), 500
        except ValueError:
            return jsonify({'success': False, 'message': 'API响应不是有效的JSON'}), 500

        if not isinstance(data, dict) or 'errcode' not in data:
            return jsonify({'success': False, 'message': 'API响应格式无效'}), 500

        if data.get('errcode') == 0:
            config.access_token = data.get('access_token', '')
            expires_in = data.get('expires_in', 7200)
            config.token_expires = datetime.now() + timedelta(seconds=expires_in - 300)
            db.session.commit()

            return jsonify({
                'success': True,
                'message': 'Token刷新成功',
                'token': (config.access_token[:10] + '...' + config.access_token[-10:]) if config.access_token else '',
                'expires': config.token_expires.strftime('%Y-%m-%d %H:%M:%S') if config.token_expires else ''
            })
        else:
            error_msg = f"获取Token失败: {data.get('errmsg', '未知错误')} (错误码: {data.get('errcode')})"
            logger.error(error_msg)
            return jsonify({'success': False, 'message': error_msg}), 400
    except Exception as e:
        logger.exception("刷新Token时发生异常")
        return jsonify({'success': False, 'message': str(e)}), 500

@wx_bp.route('/sync_logs')
def sync_logs():
    page = request.args.get('page', 1, type=int)
    per_page = 20  # 每页显示数量
    start_date = request.args.get('start')
    end_date = request.args.get('end')
    status = request.args.get('status')

    # 构建基础查询
    query = SyncLog.query

    # 添加时间筛选
    if start_date and end_date:
        start = datetime.strptime(start_date, '%Y-%m-%d')
        end = datetime.strptime(end_date, '%Y-%m-%d') + timedelta(days=1)
        query = query.filter(SyncLog.sync_time.between(start, end))
    elif start_date:
        start = datetime.strptime(start_date, '%Y-%m-%d')
        query = query.filter(SyncLog.sync_time >= start)
    elif end_date:
        end = datetime.strptime(end_date, '%Y-%m-%d') + timedelta(days=1)
        query = query.filter(SyncLog.sync_time <= end)

    # 添加状态筛选（统一使用英文状态值）
    if status and status in ['success', 'processing', 'failure']:
        query = query.filter(SyncLog.status == status)
    elif status:
        flash(f'无效的状态筛选值: {status}', 'warning')

    # 获取分页数据
    pagination = query.order_by(
        SyncLog.sync_time.desc()
    ).paginate(page=page, per_page=per_page, error_out=False)

    # 计算统计数据（基于当前筛选条件）
    total_count = query.count()
    success_count = query.filter_by(status='success').count()
    failed_count = query.filter_by(status='failure').count()
    recent_sync = query.order_by(SyncLog.sync_time.desc()).first()

    return render_template('admin/wxwork/sync_logs.html',
                         logs=pagination.items,
                         pagination=pagination,
                         total_count=total_count,
                         success_count=success_count,
                         failed_count=failed_count,
                         recent_sync=recent_sync.sync_time if recent_sync else None)

@wx_bp.route('/groups/retry_join/<int:group_user_id>', methods=['POST'])
def retry_join(group_user_id):
    group_user = GroupUser.query.get_or_404(group_user_id)
    # 这里添加实际的群组重试逻辑
    flash('操作已重试', 'info')
    return redirect(url_for('wxwork.wxindex'))

# 组织架构列表
@wx_bp.route('/departments', methods=['GET', 'POST'])
def list_departments():
    if request.method == 'POST' and request.form.get('action') == 'add_department':
        # 处理添加部门逻辑
        name = request.form.get('name')
        parent_id = request.form.get('parent_id')

    # 获取分页参数
    page = request.args.get('page', 1, type=int)
    per_page = 15  # 每页显示的顶级部门数量

    all_departments = Department.query.all()
    department_map = {dept.id: dept for dept in all_departments}

    for dept in all_departments:
        dept.children = []
        dept.user_count = dept.user_count()  # 使用模型方法计算用户数量

    root_departments = []
    for dept in all_departments:
        if dept.parent_id and dept.parent_id in department_map:
            parent = department_map[dept.parent_id]
            parent.children.append(dept)
        else:
            root_departments.append(dept)

    root_departments.sort(key=lambda x: x.order)
    for dept in all_departments:
        dept.children.sort(key=lambda x: x.order)

    # 只对顶级部门进行分页
    paginated_root = root_departments[(page-1)*per_page : page*per_page]
    total_pages = (len(root_departments) + per_page - 1) // per_page

    return render_template('admin/wxwork/departments.html',
                         active_page='departments',
                         departments=paginated_root,  # 只传递当前页的顶级部门
                         page=page,
                         per_page=per_page,
                         total_pages=total_pages,
                         has_next=page < total_pages,
                         has_prev=page > 1)

# 人员列表
@wx_bp.route('/members')
def list_members():
    from sqlalchemy.orm import joinedload
    users = User.query.options(joinedload(User.department)).order_by(User.name).all()
    departments = Department.query.all()
    return render_template('admin/wxwork/members.html',
                           users=users,
                           departments=departments)

##############群聊核心代码开始#################################群聊核心代码开始###################
@wx_bp.route('/groups')
def group_management():
    """群组管理主页面"""
    groups = Group.query.filter_by(status=Group.ACTIVE).all()
    return render_template('admin/wxwork/groups.html', groups=groups)

# 创建群组
@wx_bp.route('/groups/create', methods=['GET', 'POST'])
def create_group():
    """创建企业微信群聊（修复版）"""
    if request.method == 'POST':
        # 获取表单数据
        name = request.form.get('name')
        owner_id = request.form.get('owner_id')
        user_ids = request.form.getlist('user_ids')  # 选择的成员ID列表
        assigned_tags = request.form.get('assigned_tags', '')

        # 验证必填字段
        if not name or not owner_id:
            flash('群名称和群主为必填项', 'danger')
            return redirect(url_for('wxwork.create_group'))

        # 获取群主信息
        owner = db.session.get(User, owner_id)
        if not owner:
            flash('无效的群主', 'danger')
            return redirect(url_for('wxwork.create_group'))

        # 获取成员信息
        members = []
        if user_ids:
            members = User.query.filter(User.id.in_(user_ids)).all()

        # 企业微信API要求：创建群需要至少2人（群主+1成员）
        if len(members) < 1:
            flash('创建群需要至少选择1个成员', 'danger')
            return redirect(url_for('wxwork.create_group'))

        # 获取企业微信ID列表（确保群主包含在内）
        wecom_userids = [u.wecom_userid for u in members]

        # 企业微信要求：群主必须在userlist中
        if owner.wecom_userid not in wecom_userids:
            wecom_userids.append(owner.wecom_userid)

        # 调用API创建群聊
        chat_id = WeComSync.create_app_chat(
            name=name,
            owner=owner.wecom_userid,
            userlist=wecom_userids
        )

        if chat_id:
            # 保存群组到数据库
            group = Group(
                name=name,
                chat_id=chat_id,
                owner_id=owner_id,
                status=Group.ACTIVE,
                assigned_tags=assigned_tags
            )
            db.session.add(group)
            db.session.flush()  # 获取group.id

            # 添加成员关系
            for user in [owner] + members:  # 包含群主
                # 避免重复添加
                if not GroupUser.query.filter_by(group_id=group.id, user_id=user.id).first():
                    db.session.add(GroupUser(
                        group_id=group.id,
                        user_id=user.id,
                        status=GroupUser.ACTIVE,
                        assigned_tags=assigned_tags
                    ))

            db.session.commit()
            flash('群组创建成功', 'success')
            return redirect(url_for('wxwork.group_detail', group_id=group.id))
        else:
            flash('群组创建失败，请检查企业微信配置', 'danger')

    # GET请求显示表单
    users = User.query.all()
    return render_template('admin/wxwork/group_create.html', users=users)

# 群组详情
@wx_bp.route('/groups/<int:group_id>')
def group_detail(group_id):
    group = Group.query.get_or_404(group_id)
    users = User.query.all()  # 新增这行
    return render_template('admin/wxwork/group_detail.html', users=users, group=group)

# 添加成员到群组
@wx_bp.route('/groups/<int:group_id>/add_members', methods=['POST'])
def add_group_members(group_id):
    group = Group.query.get_or_404(group_id)
    user_ids = request.form.getlist('user_ids')

    if not user_ids:
        flash('请选择要添加的成员', 'warning')
        return redirect(url_for('wxwork.group_detail', group_id=group_id))

    # 获取成员的企业微信ID
    users = User.query.filter(User.id.in_(user_ids)).all()
    wecom_userids = [u.wecom_userid for u in users]

    if WeComSync.update_app_chat(
            group.chat_id,
            add_user_list=wecom_userids
    ):
        # 添加成员到本地数据库
        for user in users:
            if not GroupUser.query.filter_by(group_id=group_id, user_id=user.id).first():
                db.session.add(GroupUser(
                    group_id=group_id,
                    user_id=user.id,
                    status=GroupUser.ACTIVE
                ))
        db.session.commit()
        flash('成员添加成功', 'success')
    else:
        flash('添加成员失败', 'danger')

    return redirect(url_for('wxwork.group_detail', group_id=group_id))

# 更新群公告
@wx_bp.route('/groups/<int:group_id>/announcement', methods=['POST'])
def update_announcement(group_id):
    group = Group.query.get_or_404(group_id)
    content = request.form.get('content', '')

    if WeComSync.update_app_chat(
            group.chat_id,
            announcement=content
    ):
        group.announcement = content  # 更新本地缓存
        db.session.commit()
        flash('公告更新成功', 'success')
    else:
        flash('公告更新失败', 'danger')

    return redirect(url_for('wxwork.group_detail', group_id=group_id))

# 按标签加群手动触发
@wx_bp.route('/groups/<int:group_id>/add_by_tags', methods=['POST'])
def add_group_members_by_tags(group_id):
    group = Group.query.get_or_404(group_id)
    tag_names = [t.strip() for t in request.form.get('tags', '').split(',')]

    if not tag_names:
        flash('请至少输入一个标签', 'warning')
        return redirect(url_for('wxwork.group_detail', group_id=group_id))

    # 调用类方法
    if WeComSync.add_users_by_tag_to_group(group_id, tag_names):
        flash('按标签添加成员成功', 'success')
    else:
        flash('添加成员失败', 'danger')

    return redirect(url_for('wxwork.group_detail', group_id=group_id))

# 添加标签到群组
@wx_bp.route('/groups/<int:group_id>/add_tags', methods=['POST'])
def add_group_tags(group_id):
    group = Group.query.get_or_404(group_id)
    tags = request.form.get('tags', '').strip()

    if not tags:
        flash('请输入至少一个标签', 'warning')
        return redirect(url_for('wxwork.group_detail', group_id=group_id))

    # 处理标签字符串
    new_tags = [t.strip() for t in tags.split(',') if t.strip()]

    # 合并现有标签
    existing_tags = []
    if group.assigned_tags:
        existing_tags = [t.strip() for t in group.assigned_tags.split(',') if t.strip()]

    # 去重并合并
    all_tags = list(set(existing_tags + new_tags))

    # 更新群组标签
    group.assigned_tags = ','.join(all_tags)
    db.session.commit()

    flash(f'已添加 {len(new_tags)} 个标签到群组', 'success')
    return redirect(url_for('wxwork.group_detail', group_id=group_id))

# 从群组移除标签
@wx_bp.route('/groups/<int:group_id>/remove_tag/<tag>', methods=['GET'])
def remove_group_tag(group_id, tag):
    group = Group.query.get_or_404(group_id)

    if not group.assigned_tags:
        flash('该群组没有关联的标签', 'warning')
        return redirect(url_for('wxwork.group_detail', group_id=group_id))

    # 移除指定标签
    tags = [t.strip() for t in group.assigned_tags.split(',')]
    if tag in tags:
        tags.remove(tag)
        group.assigned_tags = ','.join(tags)
        db.session.commit()
        flash(f'已移除标签: {tag}', 'success')
    else:
        flash('该标签不存在于群组中', 'warning')

    return redirect(url_for('wxwork.group_detail', group_id=group_id))

# 添加群成员同步按钮
@wx_bp.route('/groups/<int:group_id>/sync_members', methods=['POST'])
def sync_group_members(group_id):
    group = Group.query.get_or_404(group_id)

    if WeComSync.sync_group_members(group.chat_id):
        flash('群成员同步成功', 'success')
    else:
        flash('群成员同步失败', 'danger')

    return redirect(url_for('wxwork.group_detail', group_id=group_id))

# 从企业微信移除成员
@wx_bp.route('/groups/<int:group_id>/remove_member/<int:user_id>', methods=['POST'])
def remove_group_member(group_id, user_id):
    group = Group.query.get_or_404(group_id)
    user = User.query.get_or_404(user_id)

    # 从企业微信移除成员
    if WeComSync.update_app_chat(
            group.chat_id,
            del_user_list=[user.wecom_userid]
    ):
        # 更新本地数据库
        GroupUser.query.filter_by(
            group_id=group_id,
            user_id=user_id
        ).delete()
        db.session.commit()
        flash(f'已移除成员 {user.name}', 'success')
    else:
        flash('移除成员失败', 'danger')

    return redirect(url_for('wxwork.group_detail', group_id=group_id))

# 新增解散群路由
@wx_bp.route('/groups/<int:group_id>/dismiss', methods=['POST'])
def dismiss_group(group_id):
    # 获取群组信息
    group = Group.query.get_or_404(group_id)

    # 获取群主信息，通过群组的 owner_id 与 User 表的 id 对应
    owner = group.owner  # 通过关系直接获取群主

    # 权限验证：只有群主可以解散群组
    if owner.id != group.owner_id:  # 修改为直接比较ID
        flash('只有群主可以解散群组', 'danger')
        return redirect(url_for('wxwork.group_management'))

    # 检查群组状态，如果已经解散则不允许再次解散
    if group.status == Group.DISMISSED:
        flash('该群组已解散', 'danger')
        return redirect(url_for('wxwork.group_management'))

    # 更新群组状态为解散中
    group.status = Group.DISMISSING
    group.dismiss_requested_at = datetime.now()  # 记录解散请求的时间
    db.session.commit()

    # 调用企业微信API进行群组解散操作
    try:
        if WeComSync.disband_app_chat(group.chat_id):  # 假设这是调用解散群组的API
            # 如果成功解散群组，将群组状态更新为已解散
            group.status = Group.DISMISSED
            db.session.commit()
            flash('群组已成功解散', 'success')
        else:
            flash('解散失败：请检查企业微信配置或群状态', 'danger')
    except Exception as e:
        db.session.rollback()  # 出现异常时回滚事务
        flash(f'解散群组失败，错误：{str(e)}', 'danger')

    return redirect(url_for('wxwork.group_management'))

# 根据标签同步群组成员
@wx_bp.route('/groups/<int:group_id>/sync_by_tags', methods=['POST'])
def sync_group_by_tags(group_id):
    """根据标签同步群组成员"""
    group = Group.query.get_or_404(group_id)

    # 先添加符合标签的新成员
    success, message = WeComSync.sync_group_by_tags(group_id)

    if success:
        flash(message, 'success')
    else:
        flash(message, 'warning')

    return redirect(url_for('wxwork.group_detail', group_id=group_id))

# 移除不符合标签要求的成员
@wx_bp.route('/groups/<int:group_id>/remove_non_matching', methods=['POST'])
def remove_non_matching_members(group_id):
    """移除不符合标签要求的成员"""
    group = Group.query.get_or_404(group_id)

    success, message = WeComSync.remove_non_matching_members(group_id)

    if success:
        flash(message, 'success')
    else:
        flash(message, 'warning')

    return redirect(url_for('wxwork.group_detail', group_id=group_id))